package mypackage;

import com.jackbe.jbp.jems.client.EMMLUserFunction;
import org.w3c.dom.*;
import org.xml.sax.InputSource;

import java.io.StringReader;

import ch.elca.el4j.services.xmlmerge.Configurer;
import ch.elca.el4j.services.xmlmerge.config.PropertyXPathConfigurer;
import ch.elca.el4j.services.xmlmerge.config.ConfigurableXmlMerge;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;


import java.io.*;
import javax.xml.parsers.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;

import org.xml.sax.*;

public class XmlMerge extends EMMLUserFunction {

    // Returns a document from the result of merging 2 documents base in a xpath expression
        public static Document mergeByMatcher(Document root1, Document root2, String xpath) {

        Document result = null;
        Configurer configurer = null;
        String[] sources = {
                convertXMLToString(root1),
                convertXMLToString(root2)
        };

        try {
            configurer = new PropertyXPathConfigurer(xpath.replace("|", "\n"));
            System.out.println("xpath.replaceAll:::::::::"+xpath.replace("|", "\n"));
            result = stringToDom(new ConfigurableXmlMerge(configurer).merge(sources));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    // Returns a document in String  from the result of merging 2 documents( Strings) base in a xpath expression    
    public static String mergeByMatcherFromString(String root1, String root2, String xpath) {

        String result = null;
        Configurer configurer = null;
        String[] sources = {
                root1,
                root2
        };

        try {
            configurer = new PropertyXPathConfigurer(xpath.replace("|", "\n"));
            result = new ConfigurableXmlMerge(configurer).merge(sources);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    // Returns a document in String  from the result of merging 2 documents( Strings) base in a xpath expression
    public static Document mergeByMatcherFromStringToDocument(String root1, String root2, String xpath) {

        Document result = null;
        Configurer configurer = null;
        String[] sources = {
                root1,
                root2
        };

        try {
            configurer = new PropertyXPathConfigurer(xpath.replace("|", "\n"));
            result = stringToDom(new ConfigurableXmlMerge(configurer).merge(sources));

        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    // Returns a document in String  from the result of merging 2 documents( Strings) base in a xpath expression
    public static String mergeByMatcherFromElement(Element root1, Element root2, String xpath) {

        String result = null;
        Configurer configurer = null;
        String[] sources = {
                convertXMLToString(root1),
                convertXMLToString(root2)
        };

        try {
            configurer = new PropertyXPathConfigurer(xpath.replace("|", "\n"));
            result = new ConfigurableXmlMerge(configurer).merge(sources);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    //Converts from String to Document
    public static Document stringToDom(String xmlSource)
            throws SAXException, ParserConfigurationException, IOException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(new InputSource(new StringReader(xmlSource)));
    }

    //Converts from Document to String
    public static String convertXMLToString(Document doc) {
        try {
            StringWriter stw = new StringWriter();
            Transformer serializer = TransformerFactory.newInstance().newTransformer();
            serializer.transform(new DOMSource(doc), new StreamResult(stw));
            return stw.toString();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //Converts from Document to String
    public static String convertXMLToString(Element doc) {
        try {
            StringWriter stw = new StringWriter();
            Transformer serializer = TransformerFactory.newInstance().newTransformer();
            serializer.transform(new DOMSource(doc), new StreamResult(stw));
            return stw.toString();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //Hardtester
    public static void main(String[] args) throws Exception {
        String[] sources = {
                "<root><a><b/></a> <d /><d /></root>",
                "<root>" +
                        "  <a>" +
                        "    <b/>" +
                        "  </a>" +
                        "  <d/>" +
                        "  <d/>" +
                        "  <x>" +
                        "    <a>" +
                        "      <c/>" +
                        "    </a>" +
                        "    <d/>" +
                        "  </x>" +
                        "</root>"};

        try {
            XmlMerge test = new XmlMerge();
            System.out.println(test.convertXMLToString(XmlMerge.mergeByMatcher
                    (test.stringToDom(sources[0]),
                            test.stringToDom(sources[1]),
                            "xpath.1=/root//d | matcher.1=ID"
                    )));

//            System.out.println(XmlMerge.mergeByMatcherFromString(
//                    sources[0],
//                    sources[1],
//                    "xpath.1=/root//d \n matcher.1=ID"
//            ));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
